<template>
  <div :class="{ 'anvil-code-vfor-table-container': true, reverse: pagePosition !== 'bottom' }">
    <div class="anvil-code-vfor-table">
      <div :style="{ width }" v-for="(formItem, index) in tableData" :key="index">
        <div :class="['vfor-card', `shadow-${shadow}`]" :style="{ '--rowGap': rowGap + 'px', '--colGap': colGap + 'px' }">
          <form-render ref="valiFormDynamic" :options="dynamicColumns[index]" :pageId="pageId" :inGrid="true" v-model:data="tableData[index]" />
        </div>
      </div>
    </div>
    <component
      :is="pagination"
      v-if="page && pageObj.total > 0"
      :total="pageObj.total"
      v-model:page="pageObj.pageNum"
      v-model:limit="pageObj.pageSize"
      layout="total,prev,pager,next,sizes,jumper"
      @pagination="
        () => {
          search();
        }
      "
    />
  </div>
</template>
  
  <script>
import FormRender from '../../views/form-render/index.vue';
import { ElMessage, ElMessageBox } from 'element-plus';
import anvilPagination from '../anvilPagination/anvilPagination.vue';
import JsonPath from 'jsonpath';
import { customApiExecute, modelApiExecute, localApiExecute, getParamsWithMerge, getJsonCallableCompList, getJsonCallableCompListWithChildren } from '../../utils/common-methods';
import { cloneDeep } from 'lodash-es';

export default {
  name: 'AnvilVforTable',
  components: { FormRender, anvilPagination },
  inheritAttrs: false,
  props: {
    pageId: {
      type: String,
      default: ''
    },
    disabled: {
      type: Boolean,
      default: false
    },
    modelValue: {
      type: [Object, String],
      default: () => {}
    },
    children: {
      type: Object,
      default: () => {}
    },
    width: {
      type: String,
      default: ''
    },
    sourceType: {
      type: String,
      default: 'remote'
    },
    ajaxSetting: {
      type: Object,
      default: () => {}
    },
    // 默认调用查询事件
    autoLoad: {
      type: Boolean,
      default: true
    },
    // 分页位置
    pagePosition: {
      type: String,
      default: 'bottom'
    },
    // 初始分页大小
    pageSize: {
      type: Number,
      default: 10
    },
    page: {
      type: Boolean,
      default: false
    },
    staticData: {
      type: Array,
      default: () => []
    },
    jsonPath: {
      type: String,
      default: ''
    },
    // 阴影样式
    shadow: {
      type: String,
      default: 'never'
    },
    rowGap: {
      type: Number,
      default: undefined
    },
    colGap: {
      type: Number,
      default: undefined
    },
    // 选择分页组件
    pagination: {
      type: String,
      default: 'anvilPagination'
    }
  },
  data() {
    return {
      tableData: [],
      dynamicColumns: [],
      pageObj: {
        pageNum: 1,
        pageSize: this.pageSize,
        total: 0
      },
      preData: undefined // 记录前data值
    };
  },
  computed: {},
  watch: {
    modelValue: {
      handler() {
        if (this.modelValue) {
          if (typeof this.modelValue == 'function') {
            this.tableData = this.modelValue();
          } else {
            this.tableData = this.modelValue;
          }
        } else {
          this.tableData = [];
        }

        // 第一次获取值时初始化渲染
        if (this.preData == undefined && this.value !== undefined) {
          this.initDynamicColumns();
          this.preData = this.value;
        }
      },
      immediate: true,
      deep: true
    },
    tableData: {
      handler(newVal, oldVal) {
        this.$emit('update:modelValue', newVal);
      },
      deep: true
    },
    // 目前外部值变化 影响内部值的只有disabled
    disabled: {
      handler(newVal) {
        this.setDynamicColsDisabled();
      },
      immediate: true
    },
    children: {
      handler(newVal) {},
      deep: true
    }
  },
  created() {
    this.initDynamicColumns();
  },
  mounted() {
    if (this.autoLoad) {
      this.search();
    }
  },
  methods: {
    // 对当前子表单内容进行校验
    validateForm(ruleIds) {
      const lines = [];
      // 表单模式
      // eslint-disable-next-line @typescript-eslint/no-this-alias
      let that = this;
      // 因为每次删除后增加子表单，ref都会增加一个最新的在数组末尾，这边直接将所有ref进行校验，最后通过promise.all
      // 只要报错就返回
      if (that.$refs['valiFormDynamic']) {
        console.log('that.$refs["valiFormDynamic"]', that.$refs['valiFormDynamic']);
        const len = that.$refs['valiFormDynamic'].length;
        for (let i = len - 1; i >= 0; i--) {
          console.log('index' + i, that.$refs['valiFormDynamic'][i]);
          lines.push(that.$refs['valiFormDynamic'][i].validateAvueForm());
          if (ruleIds) {
            const result = that.$refs['valiFormDynamic'][i].operateValidateRules(ruleIds);
            if (!result) {
              lines.push(
                Promise.reject({
                  [this.$attrs.prop]: [
                    {
                      field: this.$attrs.prop,
                      fieldValue: '',
                      message: `vfor表格的自定义校验规则校验失败`
                    }
                  ]
                })
              );
            }
          }
        }
      }

      console.log('lines', lines);
      return lines;
    },
    // 对子表单的渲染数据结构进行初始化
    initDynamicColumns() {
      this.dynamicColumns = [];
      if (this.tableData && this.tableData.length) {
        // 获取所有组件数据引用，给每个组件加上scopeRow参数
        for (let i = 0; i < this.tableData.length; i++) {
          const options = cloneDeep(this.children);
          const params = {
            scopeRow: {
              row: this.tableData[i],
              index: i
            },
            pageId: this.pageId
          };

          const compArr = getJsonCallableCompListWithChildren(options);
          console.log('compArr==========', compArr);
          compArr.map((comp) => {
            comp.params = params;
          });

          this.dynamicColumns.push(options);
        }
      }
      this.setDynamicColsDisabled();
    },
    // 接收disabled属性并传递到内部
    setDynamicColsDisabled() {
      this.dynamicColumns.map((dynCol, index) => {
        dynCol.column.map((child, idx) => {
          const { disabled } = child;
          // 如果子表单disabled为true，内部所有组件为disabled
          if (this.disabled) {
            this.dynamicColumns[index].column[idx]['disabled'] = this.disabled;
          }
          // 否则按照组件自己的disabled值赋值
          else {
            this.dynamicColumns[index].column[idx]['disabled'] = disabled;
          }
        });
      });
    },
    // 加载数据方法
    async search(query) {
      const { type, url, method, contentType, hookBefore, hookAfter, headers, params, noLoading } = this.ajaxSetting;
      if (this.sourceType == 'remote' && url) {
        const { pageNum, pageSize } = this.pageObj;

        const body = getParamsWithMerge(this, params);

        let Param = {
          pageNum,
          pageSize,
          ...this.mergeObjects(body, query)
        };

        Param = this.operateHookBefore(Param, hookBefore);

        console.log('查询参数', Param);

        const callback = (res) => {
          try {
            const Res = this.operateHookAfter(res, hookAfter);
            if (this.page) {
              this.load(Res.data.list);
              this.pageObj.total = Res.data.total;
            } else {
              this.load(Res.data);
            }
          } catch (e) {
            console.log('表格数据解析失败', e);
          }
        };

        const config = {
          url,
          method,
          contentType,
          params: Param,
          callback
        };

        switch (type) {
          case 'ajax':
            return customApiExecute(config, { noLoading: this.noLoading });
          case 'ajaxModel':
            return modelApiExecute(config, { noLoading: this.noLoading });
          case 'ajaxLocal':
            return localApiExecute(config, { noLoading: this.noLoading });
        }
      } else if (this.sourceType == 'provide' && this.jsonPath) {
        if (this.getDataFromOthers && typeof this.getDataFromOthers == 'function' && this.getDataFromOthers()) {
          const data = JsonPath.query(this.getDataFromOthers(), this.jsonPath);
          if (data && data.length) {
            if (this.page) {
              this.load(data[0]);
              this.pageObj.total = data[0].length;
            } else {
              this.load(data[0]);
            }
          }
        }
      } else if (this.sourceType == 'static' && this.staticData) {
        this.load(this.staticData);
      }
    },
    // 合并两个对象，若属性存在重复，则只取有值的
    mergeObjects(obj1, obj2) {
      const result = { ...obj1 };

      if (!obj2) {
        return result;
      }

      for (const key in obj2) {
        if (
          (typeof obj2[key] == 'string' && obj2[key] !== '') ||
          (Object.prototype.toString.call(obj2[key]) == '[object Array]' && obj2[key].length) ||
          (Object.prototype.toString.call(obj2[key]) == '[object Object]' && Object.keys(obj2[key]).length)
        ) {
          result[key] = obj2[key];
        }
      }

      return result;
    },
    // 接口调用执行前钩子
    operateHookBefore(data, hookBefore) {
      try {
        if (hookBefore) {
          const anvilCodeStore = this.useAnvilCodeStore();
          // 获取当前表单实例
          const { instance } = anvilCodeStore.getPageForm(this.pageId);
          return instance[hookBefore](data);
        } else {
          return data;
        }
      } catch (e) {
        console.log('error!', e);
        return data;
      }
    },
    operateHookAfter(data, hookAfter) {
      try {
        if (hookAfter) {
          const anvilCodeStore = this.useAnvilCodeStore();
          // 获取当前表单实例
          const { instance } = anvilCodeStore.getPageForm(this.pageId);
          return instance[hookAfter](data);
        } else {
          return data;
        }
      } catch (e) {
        console.log('error!', e);
        return data;
      }
    },
    load(data) {
      if (!data instanceof Array) {
        ElMessage.error('请传入正确数据类型！');
        return;
      }
      this.tableData = data;
      this.initDynamicColumns();
    }
  }
};
</script>
  
  <style lang="scss" scoped>
.anvil-code-vfor-table-container {
  display: flex;
  flex-direction: column;

  .anvil-code-vfor-table {
    width: 100%;
    height: auto;
    display: flex;
    flex-direction: row;
    flex-wrap: wrap;
    //   gap: 12px;

    .vfor-card {
      flex: 0 1 auto;
      transition: 0.3s;
      border-radius: 4px;
      border: 1px solid #e4e7ed;
      margin: 0 var(--colGap) var(--rowGap) 0;
    }

    .shadow-always {
      box-shadow: 0px 0px 12px rgba(0, 0, 0, 0.12);
    }

    .shadow-hover {
      &:hover {
        box-shadow: 0px 0px 12px rgba(0, 0, 0, 0.12);
      }
    }
  }
}

.reverse {
  flex-direction: column-reverse;
}
</style>
  